#include "scripting/script_semantic_analyzer.h"
#include "types/reflex.h"
#include <set>
#include <utils/utils/string_util.h>

using namespace base::utils;

namespace script
{
class ScriptSemanticAnalyzerData
{
private:
    friend class ScriptSemanticAnalyzer;
    ErrorInfo error_info;
    std::set<std::string> defined_variable;//variable

private:
    /**
     * @brief:  分析根语法树
     * @author: sherlock_lht
     */
    bool analyzeRootASTNode(const ASTNode &ast_node);
    bool analyzeASTNode(const ASTNode &ast_node);

    /**
     * @brief:  分析var语法
     * @author: sherlock_lht
     */
    bool analyzeVarDeclaration(const ASTNode &ast_node);

    /**
     * @brief:  分析function语法
     * @author: sherlock_lht
     */
    bool analyzeFunctionDeclaration(const ASTNode &ast_node);

    /**
     * @brief:  分析if语法
     * @author: sherlock_lht
     */
    bool analyzeIfSyntax(const ASTNode &ast_node);

    /**
     * @brief:  分析while循环语法
     * @author: sherlock_lht
     */
    bool analyzeWhileSyntax(const ASTNode &ast_node);

    /**
     * @brief:  分析repeat语法
     * @author: sherlock_lht
     */
    bool analyzeRepeatRetrySyntax(const ASTNode &ast_node);

    /**
     * @brief:  分析reactive语法
     * @author: sherlock_lht
     */
    bool analyzeReactiveSyntax(const ASTNode &ast_node);

    /**
     * @brief:  分析parallel语法
     * @author: sherlock_lht
     */
    bool analyzeParallelSyntax(const ASTNode &ast_node);

    bool analyzeForcePassSyntax(const ASTNode &ast_node);

    bool analyzeForceFailSyntax(const ASTNode &ast_node);

    /**
     * @brief:  分析运行标识符，即运行task语法
     * @author: sherlock_lht
     */
    bool analyzeRunIdentifierSyntax(const ASTNode &ast_node);

    /**
     * @brief:  分析表达式，包括if、while、reactive等
     * @author: sherlock_lht
     */
    bool analyzeExpression(const ASTNode &ast_node);

    /**
     * @brief:  分析not表达式，仅限被!修饰的内容
     * @author: sherlock_lht
     */
    bool analyzeNotExpression(const ASTNode &ast_node);

    /**
     * @brief:  分析and表达式，仅限被and修饰的内容
     * @author: haitao.lin
     */
    bool analyzeAndExpression(const ASTNode &ast_node);

    /**
     * @brief:  分析or表达式，仅限被or修饰的内容
     * @author: haitao.lin
     */
    bool analyzeOrExpression(const ASTNode &ast_node);

    /**
     * @brief:  分析非循环执行体
     * @author: sherlock_lht
     */
    bool analyzeNoWhileExecutant(const ASTNode &ast_node);

    /**
     * @brief:  分析循环执行体
     * @author: sherlock_lht
     */
    bool analyzeWhileExecutant(const ASTNode &ast_node);

    /**
     * @brief:  设置错误描述，如果错误描述不为空，则不设置
     * @author: sherlock_lht
     */
    void setErrorInfo(const std::string &error_msg, const ASTNode &ast_node);

    /**
     * @brief:  检查变量是否已经被声明过
     * @author: sherlock_lht
     */
    bool isVariableDefined(const std::string &variable);
};
bool ScriptSemanticAnalyzerData::analyzeRootASTNode(const ASTNode &ast_node)
{
    if (ASTNodeType::Root != ast_node.type)
    {
        setErrorInfo("not a valid ast", ast_node);
        return false;
    }
    for (const auto &node: ast_node.children)
    {
        if (!analyzeASTNode(node))
        {
            return false;
        }
    }
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeASTNode(const ASTNode &ast_node)
{
    switch (ast_node.type)
    {
        case ASTNodeType::VarDeclaration:
            return analyzeVarDeclaration(ast_node);
        case ASTNodeType::FuncDeclaration:
            return analyzeFunctionDeclaration(ast_node);
        case ASTNodeType::IfStatement:
            return analyzeIfSyntax(ast_node);
        case ASTNodeType::RepeatStatement:
        case ASTNodeType::RetryStatement:
            return analyzeRepeatRetrySyntax(ast_node);
        case ASTNodeType::WhileLoop:
            return analyzeWhileSyntax(ast_node);
        case ASTNodeType::ReactiveStatement:
            return analyzeReactiveSyntax(ast_node);
        case ASTNodeType::ParallelStatement:
            return analyzeParallelSyntax(ast_node);
        case ASTNodeType::ForcePassStatement:
            return analyzeForcePassSyntax(ast_node);
        case ASTNodeType::ForceFailStatement:
            return analyzeForceFailSyntax(ast_node);
        case ASTNodeType::Identifier:
            return analyzeRunIdentifierSyntax(ast_node);
        case ASTNodeType::Root:
            return analyzeRootASTNode(ast_node);
        default:
            setErrorInfo("invalid ast type", ast_node);
            return false;
    }
}
void ScriptSemanticAnalyzerData::setErrorInfo(const std::string &error_msg, const ASTNode &ast_node)
{
    error_info.line = ast_node.token.line;
    error_info.column = ast_node.token.column;
    error_info.error_message = error_msg;
}
bool ScriptSemanticAnalyzerData::analyzeVarDeclaration(const ASTNode &ast_node)
{
    if (ast_node.value.empty())
    {
        setErrorInfo("expected empty task after var", ast_node);
        return false;
    }
    //task variable
    std::string task_variable = ast_node.value;
    if (ast_node.children.size() != 2) //var一定有2个子节点，分别表示task type和task name
    {
        setErrorInfo("expected task name after " + task_variable, ast_node);
        return false;
    }
    //task type
    ASTNode task_type_node = ast_node.children.at(0);
    if (task_type_node.type != ASTNodeType::Identifier)
    {
        setErrorInfo("expected task type, it is should be identifier", ast_node);
        return false;
    }
    std::string task_type = task_type_node.value;
    if (!reflex::TaskReflexManager::isTypeRegistered(task_type))
    {
        setErrorInfo("task type " + task_type + " is not be registered", ast_node);
        return false;
    }
    //task name
    ASTNode task_name_node = ast_node.children.at(1);
    if (task_name_node.type != ASTNodeType::String)
    {
        setErrorInfo("expected task name, it is should be string", ast_node);
        return false;
    }
    std::string task_name = task_name_node.value;

    if (isVariableDefined(task_variable))
    {
        //重复定义
        setErrorInfo("redeclaration of ‘task " + task_variable + "(\"" + task_name + "\")", ast_node);
        return false;
    }
    defined_variable.emplace(task_variable);
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeFunctionDeclaration(const ASTNode &ast_node)
{
    //TODO
    defined_variable.emplace(ast_node.value);
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeIfSyntax(const ASTNode &ast_node)
{
    //if应该有2~3个子树，分别是判断表达式、执行语句和else执行语句
    if (!ast_node.value.empty())
    {
        setErrorInfo("if statement AST value must be empty", ast_node);
        return false;
    }
    if (ast_node.children.size() != 2 && ast_node.children.size() != 3)
    {
        setErrorInfo("if statement must have expression and then executant, and maybe an executant", ast_node);
        return false;
    }
    if (!analyzeExpression(ast_node.children.at(0)))
    {
        return false;
    }
    if (!analyzeNoWhileExecutant(ast_node.children.at(1)))
    {
        return false;
    }
    if (ast_node.children.size() == 3 && !analyzeNoWhileExecutant(ast_node.children.at(2)))
    {
        return false;
    }
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeWhileSyntax(const ASTNode &ast_node)
{
    //if应该有1~2个子树，分别是判断表达式、执行语句
    if (!ast_node.value.empty())
    {
        setErrorInfo("while statement AST value must be empty", ast_node);
        return false;
    }
    if (ast_node.children.size() != 1 && ast_node.children.size() != 2)
    {
        setErrorInfo("while statement must have expression, and may executant", ast_node);
        return false;
    }
    if (!analyzeExpression(ast_node.children.at(0)))
    {
        return false;
    }
    if (ast_node.children.size() == 2 && !analyzeWhileExecutant(ast_node.children.at(1)))
    {
        return false;
    }
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeRepeatRetrySyntax(const ASTNode &ast_node)
{
    //repeat/retry ast node的value是repeat次数，且必须是数字，子节点包含执行体，执行体可以是空的
    if (!StringUtil::isDigit(ast_node.value))
    {
        setErrorInfo("syntax error, repeat or retry count is not digit", ast_node);
        return false;
    }
    for (const auto &node: ast_node.children)
    {
        if (!analyzeNoWhileExecutant(node))
        {
            return false;
        }
    }
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeReactiveSyntax(const ASTNode &ast_node)
{
    //TODO
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeParallelSyntax(const ASTNode &ast_node)
{
    //TODO
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeForcePassSyntax(const ASTNode &ast_node)
{
    //TODO
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeForceFailSyntax(const ASTNode &ast_node)
{
    //TODO
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeRunIdentifierSyntax(const ASTNode &ast_node)
{
    if (ast_node.value.empty())
    {
        setErrorInfo("identifier name cannot be empty", ast_node);
        return false;
    }
    if (!isVariableDefined(ast_node.value))
    {
        setErrorInfo("‘" + ast_node.value + "’ " + "was not declared in this scope", ast_node);
        return false;
    }
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeExpression(const ASTNode &ast_node)
{
    if (ast_node.children.empty())
    {
        setErrorInfo("excepted expression, expression is empty", ast_node);
        return false;
    }
    //表达式node type有4种，and/or/not/identifier/or
    for (const auto &node: ast_node.children)
    {
        switch (node.type)
        {
            case ASTNodeType::AND:
                if (!analyzeAndExpression(node))
                {
                    return false;
                }
                break;
            case ASTNodeType::NOT:
                if (!analyzeNotExpression(node))
                {
                    return false;
                }
                break;
            case ASTNodeType::OR:
                if (!analyzeOrExpression(node))
                {
                    return false;
                }
                break;
            case ASTNodeType::Identifier:
                if (node.value.empty())
                {
                    setErrorInfo("expected identifier, empty identifier", node);
                    return false;
                }
                break;
            default:
                setErrorInfo("expected expression, unknown ast node type", node);
                return false;
        }
    }
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeNotExpression(const ASTNode &ast_node)
{
    if (ast_node.children.size() != 1)
    {
        setErrorInfo("expected expression or identifier after operate '!'", ast_node);
        return false;
    }
    //not的子节点必有一个，是expression或者identifier
    ASTNode node = ast_node.children.at(0);
    if (ASTNodeType::Expression == node.type)
    {
        return analyzeExpression(node);
    }
    if (ASTNodeType::Identifier == node.type)
    {
        if (node.value.empty())
        {
            setErrorInfo("expected identifier, empty identifier", node);
            return false;
        }
        return true;
    }
    setErrorInfo("expected ast node after '!'", ast_node);
    return false;
}
bool ScriptSemanticAnalyzerData::analyzeAndExpression(const ASTNode &ast_node)
{
    //and内只有identifier/not/expression
    if (ast_node.children.empty())
    {
        setErrorInfo("expected and expression, content cannot be empty", ast_node);
        return false;
    }
    for (const auto &node: ast_node.children)
    {
        if (ASTNodeType::Identifier != node.type && ASTNodeType::NOT != node.type && ASTNodeType::Expression != node.type)
        {
            return false;
        }
    }
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeOrExpression(const ASTNode &ast_node)
{
    //or内有identifier/not/and/expression
    if (ast_node.children.empty())
    {
        setErrorInfo("expected or expression, content cannot be empty", ast_node);
        return false;
    }
    for (const auto &node: ast_node.children)
    {
        if (ASTNodeType::Identifier != node.type && ASTNodeType::NOT != node.type
            && ASTNodeType::Expression != node.type && ASTNodeType::AND != node.type)
        {
            return false;
        }
    }
    return true;
}
bool ScriptSemanticAnalyzerData::analyzeNoWhileExecutant(const ASTNode &ast_node)
{
    return analyzeASTNode(ast_node);
}
bool ScriptSemanticAnalyzerData::analyzeWhileExecutant(const ASTNode &ast_node)
{
    return analyzeASTNode(ast_node);
}
bool ScriptSemanticAnalyzerData::isVariableDefined(const std::string &variable)
{
    return defined_variable.find(variable) != defined_variable.end();
}
}

namespace script
{
ScriptSemanticAnalyzer::ScriptSemanticAnalyzer()
    : d(std::make_unique<ScriptSemanticAnalyzerData>())
{

}
bool ScriptSemanticAnalyzer::analyze(const ASTNode &ast_node)
{
    return d->analyzeRootASTNode(ast_node);
}
ErrorInfo ScriptSemanticAnalyzer::getErrorInfo() const
{
    return d->error_info;
}
ScriptSemanticAnalyzer::~ScriptSemanticAnalyzer() = default;

}

